/*
Copyright (c) 2008-2009, Attigo (Hong Kong) Limited
All rights reserved.

Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:

    * Redistributions of source code must retain the above copyright notice,
      this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright notice,
      this list of conditions and the following disclaimer in the documentation
      and/or other materials provided with the distribution.
    * Neither the name of Attigo (Hong Kong) Limited nor the names of its
      contributors may be used to endorse or promote products derived from this
      software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
package com.attigohk.labs.smugjcu;

import com.kallasoft.smugmug.api.json.entity.Album;
import com.kallasoft.smugmug.api.json.entity.Image;
import com.kallasoft.smugmug.api.json.v1_2_1.APIVersionConstants;
import com.kallasoft.smugmug.api.json.v1_2_1.login.WithPassword;
import java.io.File;
import java.io.FileFilter;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.activation.MimetypesFileTypeMap;

/**
 * Actual generation of upload list and uploading is done here.
 */
public class Processor {

    /**
     * SmugMug API Key
     */
    static String API_KEY = "vgN8I2EBDCOlga8LTpQzcVvKuckNSpEs";


    public static String[] JPEG_FILE_EXTENSIONS = { ".jpg",".jpeg" };
    private WithPassword.WithPasswordResponse response = null;

    /**
     * Checks to see if a file is eligible for upload.
     */
    private static FileFilter SUPPORTED_FILES = new FileFilter() {

        public boolean accept(File file) {
            if (!file.exists()) {
                return false;
            }
            boolean accept = false;
            for (Format f : Format.values()) {
                for (int i = 0; i < f.extensions.length; i++) {
                    if (file.getName().toLowerCase().endsWith(f.extensions[i])) {
                        accept = true;
                        break;
                    }
                }
                if (accept) {
                    break;
                }
            }
            return accept;
        }
    };


    private List<File> files;

    public Processor(File file, String username, String password, int albumId,
            boolean preventDuplicates) {
        /* Create an instance of the WithPassword method */
        WithPassword withPassword = new WithPassword();

        /* Execute the login, passing the arguments provided */
        response =
                withPassword.execute(APIVersionConstants.SECURE_SERVER_URL,
                API_KEY, username, password);



        if (file.isFile()) {
            File[] temp = new File[1];
            temp[0] = file;
            files = Arrays.asList(temp);
        } else {// is directory

            files = getSupportedFiles(file);
        }

        if (preventDuplicates) {

            System.out.print("Scanning for duplicates");
            com.kallasoft.smugmug.api.json.v1_2_1.albums.Get albumGet =
                    new com.kallasoft.smugmug.api.json.v1_2_1.albums.Get();

            com.kallasoft.smugmug.api.json.v1_2_1.albums.Get.GetResponse albums
                    = albumGet.execute(APIVersionConstants.SECURE_SERVER_URL,
                    API_KEY, response.getSessionID(), false);

            List<Album> albumsList = albums.getAlbumList();

            // find the album we're trying to upload to
            Iterator<Album> i = albumsList.iterator();
            boolean notDone = true;
            Album album = null;
            while (i.hasNext() && notDone) {
                album = i.next();
                if (album.getID() == albumId) {
                    notDone = false;
                }
            }


            if (album != null) {
                try {
                    String albumKey = album.getAlbumKey();
                    int ignoreCount = 0;
                    // Get all of the images in the album
                    com.kallasoft.smugmug.api.json.v1_2_1.images.Get imagesGet
                            = new com.kallasoft.smugmug.api.json.v1_2_1.images.Get();
                    com.kallasoft.smugmug.api.json.v1_2_1.images.Get.GetResponse
                            images = imagesGet.execute(
                            APIVersionConstants.SECURE_SERVER_URL, API_KEY,
                            response.getSessionID(), albumId, albumKey, true);
                    List<Image> imageList = images.getImageList();
                    // Calculate MD5SUM of each upload candidate and compare to
                    // those in list
                    Iterator<File> it = files.iterator();
                    List<File> removeList = new java.util.LinkedList();
                    boolean image = false;
                    while (it.hasNext() && imageList.size() > 0) {
                        File candidate = it.next();
                        System.out.print(".");
                        if (new MimetypesFileTypeMap().getContentType(candidate).contains("image")) {
                            image = true;
                            //System.out.println(candidate.getName() + " is an image.");
                        } else {
                            image = false;
                            //System.out.println(candidate.getName() + " is not an image.");
                        }


                        String md5sum = null;

                        if (image) {
                            md5sum = org.apache.commons.codec.digest.DigestUtils.md5Hex(
                                    new FileInputStream(candidate));
                        }

                        // See if an image matching the md5sum already exists
                        // and remove from upload list
                        Iterator<Image> imgIt = imageList.iterator();
                        boolean found = false;
                        while (imgIt.hasNext() && !found) {
                            Image current = imgIt.next();
                            if (image) {
                                //System.out.println("Compare " + md5sum + " and " + current.getMD5Sum());
                                if (current.getMD5Sum().equalsIgnoreCase(md5sum)) {
                                    removeList.add(candidate);
                                    found = true;
                                    ignoreCount++;
                                }
                            } else {// not image (probably video). compare filename
                                if(current.getFileName().equals(candidate.getName())) {
                                    removeList.add(candidate);
                                    found = true;
                                    ignoreCount++;
                                }
                            }
                        }
                    }

                    // Remove all duplicates from upload list
                    files.removeAll(removeList);

                    if (ignoreCount == 0) {
                        System.out.println("Found no duplicates.");
                    } else {
                        System.out.println("Found " + ignoreCount + " duplicate(s).");
                    }


                } catch (IOException ex) {
                    Logger.getLogger(Processor.class.getName()).log(Level.SEVERE, null, ex);
                }
            } else {
                System.out.println("Album does not exist.");
            }

        }

        System.out.println("Preparing to upload " + files.size() +
                " files to SmugMug album " + albumId + "...");
        Iterator<File> i = files.iterator();
        while (i.hasNext()) {
            try {
                File pic = i.next();
                long fileSize = pic.length();
                Date start = new Date();
                System.out.println("Uploading " + pic);
                com.kallasoft.smugmug.api.json.v1_2_1.images.UploadHTTPPut
                        upload = new com.kallasoft.smugmug.api.json.v1_2_1.images.UploadHTTPPut();

                upload.execute(APIVersionConstants.BINARY_UPLOAD_SERVER_URL, 
                        response.getSessionID(), albumId, null, pic.getName(),
                        new FileInputStream(pic));
                Date stop = new Date();
                long time = stop.getTime() - start.getTime();
                int seconds = (int) (time / 1000);
                int bytesPerSec = (int) (fileSize / seconds);
                int kiloBytesPerSecond = bytesPerSec / 1024;
                System.out.println("...finished in " + seconds + " seconds @ " +
                        kiloBytesPerSecond + " kilobytes/sec\n");

            } catch (FileNotFoundException ex) {
                Logger.getLogger(Processor.class.getName()).log(Level.SEVERE, null, ex);
            }
        }

    }

    private List<File> getSupportedFiles(File startingDirectory) {
        List<File> result = new ArrayList<File>();
        File[] filesAndDirs = startingDirectory.listFiles();
        List<File> filesDirs = Arrays.asList(filesAndDirs);
        for (File file : filesDirs) {
            if (SUPPORTED_FILES.accept(file) && !file.isDirectory()) {
                result.add(file);
            }

            if (!file.isFile()) {
                // a directory - make recursive call
                List<File> deeperList = getSupportedFiles(file);
                result.addAll(deeperList);
            }

        }
        return result;
    }
}
